package com.ltsh.fim.common.utils;


import com.ltsh.fim.common.model.RpcResponse;
import io.netty.buffer.ByteBuf;

import java.io.UnsupportedEncodingException;

/**
 * Created by fengjianbo on 2018/6/15 0015.
 */
public class DubboUtils {
    // magic header.
    protected static final short MAGIC = (short) 0xdabb;
    // message flag.
    protected static final byte FLAG_REQUEST = (byte) 0x80;
    protected static final byte FLAG_TWOWAY = (byte) 0x40;
    protected static final byte FLAG_EVENT = (byte) 0x20;
    
    public static byte[] getHeader(long requestId, int len, boolean twoWay, boolean event) {
        // header.
        byte[] header = new byte[Constant.HEADER_LENGTH];
        // set magic number.
        Bytes.short2bytes(MAGIC, header);

        // set request and serialization flag.
        header[2] = (byte) (FLAG_REQUEST | 6);

        if (twoWay) header[2] |= FLAG_TWOWAY;
        if (event) header[2] |= FLAG_EVENT;

        // set request id.
        Bytes.long2bytes(requestId, header, 4);

        // encode request data.

        Bytes.int2bytes(len, header, 12);
        return header;
    }

    /**
     * Demo为简单起见，直接从特定字节位开始读取了的返回值，demo未做：
     * 1. 请求头判断
     * 2. 返回值类型判断
     *
     * @param byteBuf
     * @return
     */
    public static Object decode1(ByteBuf byteBuf){

        int initReaderIndex = byteBuf.readerIndex();

        int readable = byteBuf.readableBytes();

        byte[] bytes = new byte[readable];
        byteBuf.readBytes(bytes);
        byteBuf.readerIndex(initReaderIndex);
        if (readable < Constant.HEADER_LENGTH) {
            return DubboUtils.DecodeResult.NEED_MORE_INPUT;
        }
        byteBuf.readerIndex(initReaderIndex + 4);
        long requestId = byteBuf.readLong();
        int len = byteBuf.readInt();

        int tt = len + Constant.HEADER_LENGTH;
        if (readable < tt) {
            return DubboUtils.DecodeResult.NEED_MORE_INPUT;
        }

//        byteBuf.readerIndex(byteBuf.readerIndex());
        byte[] data = new byte[len];
        byteBuf.readBytes(data);
        byteBuf.readerIndex(tt + initReaderIndex);
        RpcResponse response = new RpcResponse();
        response.setRequestId(String.valueOf(requestId));
        response.setBytes(data);
        return response;
    }
    /**
     * Demo为简单起见，直接从特定字节位开始读取了的返回值，demo未做：
     * 1. 请求头判断
     * 2. 返回值类型判断
     *
     * @param byteBuf
     * @return
     */
    public static Object decode2(ByteBuf byteBuf){
        int initReaderIndex = byteBuf.readerIndex();
        int readable = byteBuf.readableBytes();

        byte[] bytes = new byte[readable];
        byteBuf.readBytes(bytes);
        byteBuf.readerIndex(initReaderIndex);
        if (readable < Constant.HEADER_LENGTH) {
            return DubboUtils.DecodeResult.NEED_MORE_INPUT;
        }
        byteBuf.readerIndex(initReaderIndex + 4);
        long requestId = byteBuf.readLong();
        int len = byteBuf.readInt();

        int tt = len + Constant.HEADER_LENGTH;
        if (readable < tt) {
            return DubboUtils.DecodeResult.NEED_MORE_INPUT;
        }

        byteBuf.readerIndex(byteBuf.readerIndex() + 1 + Constant.SEPARATOR_LENGTH);
        byte[] data = new byte[len - 1 - Constant.SEPARATOR_LENGTH * 2];
        byteBuf.readBytes(data);
        byteBuf.readerIndex(tt + initReaderIndex);
        RpcResponse response = new RpcResponse();
        response.setRequestId(String.valueOf(requestId));
        response.setBytes(data);
        return response;
    }

    public static void encodeRequestData(ByteBuf buffer, Object data) throws Exception {
        RpcInvocation inv = (RpcInvocation)data;
        buffer.writeBytes(getBytes(inv.getAttachment("dubbo", "2.0.1")));
        buffer.writeBytes(lineBytes);
        buffer.writeBytes(getBytes(inv.getAttachment("path")));
        buffer.writeBytes(lineBytes);
        buffer.writeBytes(getBytes(inv.getAttachment("version")));
        buffer.writeBytes(lineBytes);
        buffer.writeBytes(getBytes(inv.getMethodName()));
        buffer.writeBytes(lineBytes);
        buffer.writeBytes(getBytes(inv.getParameterTypes()));
        buffer.writeBytes(lineBytes);
        buffer.writeBytes(getBytes(new String(inv.getArguments())));
        buffer.writeBytes(lineBytes);
        buffer.writeBytes("{}".getBytes());
        buffer.writeBytes(lineBytes);
    }
    private static byte[] nulValue =  "null".getBytes();
    private static byte[] lineBytes = System.getProperty("line.separator").getBytes();
    public static byte[] getBytes(String str) {
        try {
            if(str == null){
                return nulValue;
            } else {
                return ("\"" + str + "\"").getBytes(Constant.CHARSET_NAME);
            }

        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            return null;
        }
    }
    public enum DecodeResult {
        NEED_MORE_INPUT, SKIP_INPUT
    }
}

